﻿using System.Collections.Generic;
using System.Linq;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;
using Cms.Utilities;

namespace Cms.Application.WebFramework.Presenters
{
    public class RequestDetailsPresenter : BasePresenter
    {
        public RequestDetailsPresenter()
            : this(new RepositoryFactory())
        {
        }

        public RequestDetailsPresenter(IRepositoryFactory repositoryFactory)
            : base(repositoryFactory)
        {
        }

        public bool IsSystemPageRequest(string foldersAndPage)
        {
            foldersAndPage = foldersAndPage.ToLower();
            // If the URL is http://www.acme.com/stuff/gear.aspx then foldersAndPage is stuff/gear.aspx)
            if (foldersAndPage.StartsWith("admin/"))
            {
                return true;
            }
            switch (foldersAndPage)
            {
                case "install.aspx":
                case "webresource.axd":
                case "scriptresource.axd":
                case "authentication.asmx/":
                case "authentication.asmx/js":
                case "authentication.asmx/jsdebug":
                case "ssoauth.ashx":
                    return true;
            }
            return false;
        }

        // This method exists because the .NET way of checking if a page is protected or not is not supported under medium trust
        public bool SingleSignOnAuthorizationRequired(string foldersAndPage)
        {
            foldersAndPage = foldersAndPage.ToLower();
            if (foldersAndPage.StartsWith("admin/"))
            {
                if (foldersAndPage == "admin/ping.aspx" || 
                    foldersAndPage.StartsWith("admin/edit_area/") || 
                    foldersAndPage.StartsWith("admin/tiny_mce/") ||
                    foldersAndPage.StartsWith("admin/css/") || 
                    foldersAndPage.StartsWith("admin/img/") || 
                    foldersAndPage.StartsWith("admin/js/"))
                {
                    return false;
                }
                return true;
            }
            if (foldersAndPage == "ssoauth.ashx")
            {
                return true;
            }
            return false;
        }

        public bool IsSitePreview(string foldersAndPage)
        {
            if (foldersAndPage.ToLower() == "admin/sitepreview.aspx")
            {
                return true;
            }
            if (foldersAndPage.ToLower().EndsWith("/applicationpagepreview.aspx"))
            {
                return true;
            }
            return foldersAndPage.ToLower().EndsWith("admin/contentpreview.aspx");
        }

        public Site GetSite(string domain)
        {
            IList<Site> sites = SiteRepository.GetSites();

            // Check all main domains first (main domains take precedence over aliases)
            foreach (Site site in sites)
            {
                if (site.Domain.ToLower() == domain.ToLower())
                {
                    return site;
                }
            }

            // If no site was found, continue by examining their aliases
            foreach (Site site in sites)
            {
                foreach (string alias in site.AliasDomains)
                {
                    if (alias.ToLower() == domain.ToLower())
                    {
                        return site;
                    }
                }
            }
            return null;
        }

        public Locale GetLocaleByAliasDomain(string domain)
        {
            return LocaleRepository.GetLocales().FirstOrDefault(locale => locale.AliasDomain != null && locale.AliasDomain.ToLower() == domain.ToLower());
        }
        
        public Page GetPage(Site site, IList<string> requestFolders, bool firstFolderIsLocaleCode, string pageFilename, int administratorID)
        {
            IList<Folder> folders = SiteRepository.GetRootFolders(site); // Start with the topmost folders (root folders)
            int i = 0;
            Folder currentFolder = null;
            if (firstFolderIsLocaleCode)
            {
                i++;
            }

            // Check that the folders in the request exists, starting from the root folders and down.
            while (i < requestFolders.Count)
            {
                // Check all folders on this level and look for a matching name
                foreach (Folder f in folders)
                {
                    if (f.Name.ToLower() == requestFolders[i].ToLower())
                    {
                        currentFolder = f;
                        break;
                    }
                }
                if (currentFolder == null)
                    return null; // One of the requested folders doesn't exist
                else
                {
                    folders = currentFolder.SubFolders;
                    i++;
                }
            }
            IList<Page> pages = PageRepository.GetPages(site.ID, currentFolder == null ? -1 : currentFolder.ID);
            Page page = pages.FirstOrDefault(p => p.Filename.ToLower() == pageFilename.ToLower());
            if (administratorID > 0)
                return page;
            if (page == null || !page.IsPublishedNow())
                return null;
            return page;
        }

        public MasterTemplate GetMasterTemplate(int id)
        {
            return SiteRepository.GetMasterTemplate(id);
        }
        
        public DetailTemplate GetDetailTemplate(int id)
        {
            return SiteRepository.GetDetailTemplate(id);
        }
        
        public Page GetPage(int id)
        {
            return PageRepository.GetPage(id);
        }
        
        public Locale GetLocale(int id)
        {
            return LocaleRepository.GetLocale(id);
        }

        public ContentTranslationVersion GetContentTranslationVersion(int id)
        {
            return ContentRepository.GetContentTranslationVersion(id);
        }

        public MediaFile GetMediaFile(Site site, IList<string> requestFolders, string filename)
        {
            IList<MediaFolder> mediaFolders = SiteRepository.GetRootMediaFolders(site);

            // Start with the topmost folders (root folders)
            int i = 1;
            MediaFolder currentMediaFolder = null;

            // Check that the folders in the request exists, starting from the root folders and down.
            while (i < requestFolders.Count)
            {
                // Check all folders on this level and look for a matching name
                foreach (MediaFolder f in mediaFolders)
                {
                    if (f.Name.ToLower() == requestFolders[i].ToLower())
                    {
                        currentMediaFolder = f;
                        break;
                    }
                }
                if (currentMediaFolder == null)
                    return null; // One of the requested folders doesn't exist
                else
                {
                    mediaFolders = currentMediaFolder.SubFolders;
                    i++;
                }
            }
            IList<MediaFile> files = MediaRepository.GetMediaFiles(site.ID, currentMediaFolder == null ? -1 : currentMediaFolder.ID);
            var mediaFile = files.FirstOrDefault(f => f.Name.ToLower() == filename.ToLower());
            if (mediaFile != null)
            {
                // Re-fetch the mediafile with the complete graph
                MediaRepository.GetMediaFile(mediaFile.ID);
            }
            return mediaFile;
        }

        public RssFeed GetRssFeed(Site site, string filename)
        {
            return ContentRepository.GetRssFeed(site.ID, filename);
        }

        public bool AdministratorHasForcedLogout(int adminID)
        {
            Administrator admin = AdministratorRepository.GetAdministrator(adminID);
            if (admin != null && admin.ForceLogout)
            {
                admin.ForceLogout = false;
                AdministratorRepository.SaveAdministrator(admin);
                return true;
            }
            return false;
        }
        
        public bool AdministratorHasNoCurrentSite(int adminID)
        {
            Administrator admin = AdministratorRepository.GetAdministrator(adminID);
            return admin != null && admin.CurrentSite == null;
        }

        public bool AdministratorCanConfigureFirstSite(int adminID)
        {
            Administrator admin = AdministratorRepository.GetAdministrator(adminID);
            return admin.CurrentSite == null && admin.AvailableSites.Count == 0 &&
                   admin.HasPermission.ConfigureFirstSite;
        }

        public string GetNextDomainToCheck(string alreadyCheckedDomains)
        {
            IList<Site> sites = SiteRepository.GetSites();
            foreach (Site site in sites)
            {
                if (!IsChecked(site.Domain, alreadyCheckedDomains))
                {
                    return site.Domain;
                }
                foreach (string siteAlias in site.AliasDomains)
                {
                    if (!IsChecked(siteAlias, alreadyCheckedDomains))
                    {
                        return siteAlias;
                    }
                }
                foreach (Locale locale in site.Locales)
                {
                    if (locale.AliasDomain != null && !IsChecked(locale.AliasDomain, alreadyCheckedDomains))
                    {
                        return locale.AliasDomain;
                    }
                }
            }
            return string.Empty;
        }

        private bool IsChecked(string domain, string alreadyCheckedDomains)
        {
            return alreadyCheckedDomains.Split(",".ToCharArray()).Any(d => domain.ToLower() == d.ToLower());
        }

        public string GetAdministratorEncryptedCredentials(int adminId)
        {
            Administrator admin = AdministratorRepository.GetAdministrator(adminId);
            return Cipher.Encrypt(admin.Username + (char)9 + admin.Password);
        }

        public Administrator GetAdministrator(int adminId)
        {
            return AdministratorRepository.GetAdministrator(adminId);
        }

        public User GetUser(int userId)
        {
            return UserRepository.GetUser(userId);
        }
    }
}